With recursive descent parsers, an Abstract Syntax Tree (AST) can be thought of as a subset of the full parse tree.
Each node of the AST holds the phrase that was matched at the corresponding parse tree node.
The AST is very useful for translating the parsed string.
apg parsers generate ASTs and apg-exp uses the AST internally for all except the test() functions.
Additionally, it always makes it available to the user as well.
This example assumes that you are already familiar with the AST object in apg parsers.
If not, check out the ./src/ast examples to get started.
We will use the floating point grammar and put the numbers in normal form as we did in the ./src/Folat example
except this time we will do it with a translation of the AST.
(function ast() {
const apgJs = require('apg-js');
const writeHtml = require('../writeHtml');
const Float = require('./grammars/float');
const { apgExp: ApgExp } = apgJs;
const { apgLib } = apgJs;
const id = apgLib.ids;
const { charsToString } = apgLib.utils;
const astFloat = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.sign = '';
data.integer = '0';
data.fraction = '0';
data.esign = '+';
data.exp = 0;
} else if (state === id.SEM_POST) {
const exponent = data.exp === 0 ? '' : `e${data.esign}${data.exp}`;
data.normal = `${data.sign + data.integer}.${data.fraction}${exponent}`;
}
return ret;
};
const astSign = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
if (chars[phraseIndex] === 45) {
data.sign = '-';
}
}
return ret;
};
const astInteger = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.integer = charsToString(chars, phraseIndex, phraseLength);
}
return ret;
};
const astFraction = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.fraction = charsToString(chars, phraseIndex, phraseLength);
}
return ret;
};
const astEsign = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.esign = charsToString(chars, phraseIndex, phraseLength);
}
return ret;
};
const astExp = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
const exp = charsToString(chars, phraseIndex, phraseLength);
data.exp = parseInt(exp, 10);
}
return ret;
};
try {
let result;
let str;
let html;
const grammar = new Float();
console.log();
console.log('AST demonstration');
str = '';
str += '|||123|||123.|||.123|||-1.23|||+.123|||123.e2|||+.123E+1|||-123.123456789e-10|||';
str += '123e0|||+1.23e-0|||-.123e-001|||123e-000|||';
console.log();
console.log('input string:');
console.log(str);
const flags = 'g';
const exp = new ApgExp(grammar, flags);